Relación N:M a dos FK como clave primaria compuesta

Guía completa paso a paso para entender por qué en una relación muchos a muchos se utilizan las dos claves foráneas como clave primaria compuesta, cuándo usar una PK artificial y cómo diseñar correctamente tablas intermedias en SQL.

Bloque 1 · Concepto base

¿Qué es una relación N:M?

Una relación N:M (muchos a muchos) ocurre cuando:

Ejemplo clásico

Entidad Relación
Alumno Puede estar en muchos cursos
Curso Puede tener muchos alumnos

Esto NO puede representarse directamente en SQL con una sola FK.

Por eso aparece una tabla intermedia

Matricula
---------
id_alumno
id_curso
La tabla intermedia representa la RELACIÓN entre dos entidades.
Bloque 2 · Identidad real

¿Qué identifica realmente una fila?

La pregunta clave es:

¿Qué hace única una matrícula?

No es un número inventado.

Lo que realmente identifica la fila es:

Por tanto

PRIMARY KEY (id_alumno, id_curso)

La combinación de ambas claves foráneas ya es única.

Eso significa que:

La PK compuesta representa la identidad REAL de la relación.
Bloque 3 · Problema de PK artificial

¿Qué ocurre si usas una PK artificial?

Muchas personas crean algo así:

CREATE TABLE matricula (

 id_matricula INT PRIMARY KEY,
 id_alumno INT,
 id_curso INT

);

Problema

SQL solo controla que id_matricula no se repita.

Pero NO controla duplicados lógicos.

Ejemplo

1 | 14 | 3
2 | 14 | 3

Para SQL son filas distintas.

Pero en el mundo real:

El alumno 14 está repetido en el curso 3.

¿Cómo se arregla?

ALTER TABLE matricula
ADD CONSTRAINT uq_alumno_curso
UNIQUE(id_alumno, id_curso);

Al final acabas teniendo:

Bloque 4 · PK compuesta correcta

Ejemplo correcto con PK compuesta

Tablas principales

CREATE TABLE alumno (

 id_alumno INT PRIMARY KEY,
 nombre VARCHAR(50)

);

CREATE TABLE curso (

 id_curso INT PRIMARY KEY,
 nombre VARCHAR(50)

);

Tabla intermedia

CREATE TABLE matricula_compuesta (

 id_alumno INT,
 id_curso INT,
 fecha DATE,

 PRIMARY KEY(id_alumno, id_curso),

 FOREIGN KEY(id_alumno)
 REFERENCES alumno(id_alumno),

 FOREIGN KEY(id_curso)
 REFERENCES curso(id_curso)

);

Inserción válida

INSERT INTO matricula_compuesta
VALUES (1, 10, '2024-09-01');

Duplicado

INSERT INTO matricula_compuesta
VALUES (1, 10, '2024-09-15');
ERROR → la PK compuesta detecta duplicado automáticamente.
Bloque 5 · Cuándo sí usar PK artificial

¿Cuándo sí tiene sentido una PK artificial?

Cuando la tabla intermedia tiene vida propia.

Ejemplo real

CREATE TABLE detalle_pedido (

 id_detalle INT PRIMARY KEY,

 id_pedido INT,
 id_producto INT,

 cantidad INT,
 precio NUMERIC(10,2),
 descuento NUMERIC(10,2)

);

Aquí cambia el escenario

Entonces

La fila sí representa una entidad propia.

Si la tabla tiene datos propios importantes → PK artificial.
Bloque 6 · Comparativa

PK compuesta vs PK artificial

PK compuesta PK artificial
Relación pura Entidad propia
Más simple Más flexible
Evita duplicados automáticamente Necesita UNIQUE
Menos índices Más índices
Más normalizado Útil para históricos

Ejemplos de PK compuesta

Ejemplos de PK artificial

Bloque 7 · Casos reales

Casos prácticos explicados

Usuario ↔ Rol

PRIMARY KEY(id_usuario, id_rol)

Un usuario no debería tener el mismo rol dos veces.

Profesor ↔ Departamento

Aquí suele usarse PK artificial.

¿Por qué?

Porque puede existir histórico:

7 | 3 | 2023
7 | 3 | 2025

El mismo profesor vuelve al mismo departamento en otra fecha.

Entonces

id_asignacion INT PRIMARY KEY
Las relaciones con histórico suelen necesitar PK artificial.
Bloque 8 · Reglas profesionales

Regla mental definitiva

Usa PK compuesta cuando:

Usa PK artificial cuando:

Pregunta clave: “¿La tabla representa SOLO una relación o representa una entidad propia?”

Mini-Test Final

1. ¿Por qué se usa una PK compuesta en una relación N:M pura?

2. ¿Qué problema aparece con una PK artificial sin UNIQUE?

3. ¿Cuándo suele usarse PK artificial?